
#include "tux.h"

#include "FileTransferManager.h"
#include "FileTransferEntry.h"
#include "MsnMessage.h"
#include "MsnSession.h"
#include "MsnEvent.h"


IMPLEMENT_DYNAMIC_CLASS(FileTransferEvent, wxCommandEvent)


FileTransferManager::FileTransferManager(MsnSession* s) : session(s)
{

}

FileTransferManager::~FileTransferManager()
{
	DEBUG(_T("~FileTransferManager"));

	for(FileTransferEntryMap::iterator it = entryMap.begin(); it != entryMap.end(); ++it){
        FileTransferEntry* item = it->second;
        delete item;
    }

	//TODO delete all entries
}

void FileTransferManager::AddEntry(const wxString& id, FileTransferEntry* entry)
{
	wxMutexLocker lock(entryMapMutex);
	entryMap[id] = entry;
}

void FileTransferManager::DeleteEntry(const wxString& id)
{
	wxMutexLocker lock(entryMapMutex);

	FileTransferEntry* item = GetEntry(id);

//	entryMap.erase(id);

//	wxDELETE(item);	
}

FileTransferEntry* FileTransferManager::GetEntry(const wxString& id)
{
	wxMutexLocker lock(entryMapMutex);

	FileTransferEntryMap::iterator it = entryMap.find(id);

	if(it != entryMap.end()){
		return it->second;
	}else{
		return NULL;
	}
}

wxString FileTransferManager::FindSessionID(const wxString& callID)
{
	wxMutexLocker lock(entryMapMutex);

	for(FileTransferEntryMap::iterator it = entryMap.begin(); it != entryMap.end(); ++it){
        FileTransferEntry* entry = it->second;

		if(callID.IsSameAs(entry->GetCallID())){
			return entry->GetID();
		}
    }
	return wxEmptyString;
}


void FileTransferManager::CancelTransfer(const wxString& sessionID)
{
	FileTransferEntry* item = GetEntry(sessionID);

	item->CancelTransfer();

	DeleteEntry(item->GetID());
}

void FileTransferManager::CancelTransfer(FileTransferEntry* item)
{
	item->CancelTransfer();

	DeleteEntry(item->GetID());
}




bool FileTransferManager::WriteFileData(P2PMessage* msg)
{
	//DEBUG(_T("AppendFileData"));

	int dataSize = msg->GetHeader()->dataSize;
	int dataOffset = msg->GetHeader()->dataOffset;
	int messageLength = msg->GetHeader()->messageLength;
	wxString sessionID = wxString::Format(_T("%d"), msg->GetHeader()->sessionID);
	
	FileTransferEntry* item = GetEntry(sessionID);

	//TODO check offset

	//first chunk
	if(dataOffset == 0){
		item->SetFileSize(dataSize);
		bool result = item->OpenFile(false);
		if(!result){
			
			///todo handle error   
			
		}
    }

	//write data into file
	wxMemoryBuffer& slpBuffer = msg->GetSlpBuffer();

	item->WriteFileData((char*)slpBuffer.GetData(), slpBuffer.GetDataLen());

	//transfer done, close file
	if(dataSize == dataOffset + messageLength){	
		item->CloseFile();	

		return true;
	}

	return false;
}

bool FileTransferManager::ReadFileData(const wxString& sessionID, char* buf, int size, int& actualRead)
{
	FileTransferEntry* item = GetEntry(sessionID);	

	if(item == NULL) return false;

	//open file
	if(item->GetFileOffset() == 0){
		if(item->OpenFile(true)){
			//generate a messageID for the transfer 
			item->SetMessageID(NumberUtil::RandInt());
		}else{
			//TODO handle error
		}
	}

	if(item->IsDone()){
		return true;
	}

    actualRead = item->ReadFileData(buf, size);

	if(item->IsDone()){
		item->CloseFile();
		return true;	
	}

	return false;
}


void FileTransferManager::NotifyUpdatedEvent(const wxString& cookie, int transferredSize)
{
	FileTransferEntry* item = GetEntry(cookie);

	//already cancelled
	if(item == NULL) return;
	
	item->notifySize += transferredSize;

	time_t now = wxDateTime::GetTimeNow();
	if(now - item->notifyTime >= 1){

		FileTransferEvent event(EVT_MSN_FILE_TRANSFER_UPDATED, -1);

		event.SetClientData(item);
		event.SetSession(session);
		event.SetCookie(cookie);
		event.SetTransferSize(item->notifySize);
		event.SetTransferSpeed(item->notifySize / (now - item->notifyTime));

		session->PostEvent(event);	

		item->notifyTime = now;
		item->notifySize = 0;
	}
}

void FileTransferManager::NotifyStartedEvent(const wxString& cookie)
{
	FileTransferEntry* item = GetEntry(cookie);

	wxCommandEvent event(EVT_MSN_FILE_TRANSFER_STARTED, -1);
	event.SetString(cookie);
	event.SetClientData(item);
			
	session->PostEvent(event);	
}

void FileTransferManager::NotifyFinishedEvent(const wxString& cookie)
{
	FileTransferEntry* item = GetEntry(cookie);

	//already finished
	if(item == NULL) return;

	if(item->GetAppID() == MSN_P2P_APP_ID_DISPLAY_PICTURE){
		return;
	}


	if(item->IsDone()){
		wxCommandEvent event(EVT_MSN_FILE_TRANSFER_DONE, -1);
		event.SetString(cookie);
		event.SetClientData(item);			
		session->PostEvent(event);
	}else{
		wxCommandEvent event(EVT_MSN_FILE_TRANSFER_CANCELLED, -1);
		event.SetString(cookie);
		event.SetClientData(item);
		session->PostEvent(event);
	}

	DeleteEntry(cookie);
}

void FileTransferManager::NotifyFailedEvent(const wxString& cookie)
{
	DeleteEntry(cookie);

	wxCommandEvent event(EVT_MSN_FILE_TRANSFER_FAILED, -1);
	event.SetString(cookie);
	event.SetClientData(session);
			
	session->PostEvent(event);
}

